<!DOCTYPE html>
<script src="../../../resources/testharness.js"></script>
<script src="../../../resources/testharnessreport.js"></script>
<script src="../../../resources/gesture-util.js"></script>
<style>
div {
  position: absolute;
}
#scroller {
  width: 500px;
  height: 500px;
  overflow: scroll;
  scroll-snap-type: both mandatory;
  border: solid black 5px;
}
#space {
  width: 2000px;
  height: 2000px;
}
.target {
  width: 200px;
  height: 200px;
  scroll-snap-align: start;
  background-color: blue;
}
</style>

<body style="margin:0" onload=runTests()>
  <div id="scroller">
    <div id="space"></div>
    <div class="target" style="left: 0px; top: 0px;"></div>
    <div class="target" style="left: 80px; top: 80px;"></div>
    <div class="target" style="left: 200px; top: 200px;"></div>
  </div>
</body>

<script>
if (window.internals)
  internals.runtimeFlags.overscrollCustomizationEnabled = true;

var scroller = document.getElementById("scroller");
var space = document.getElementById("space");

function scrollPos() {
  // Combine the x and y scroll offsets since snap type is 'both'.
  return (scroller.scrollLeft << 16) + scroller.scrollTop;
}

var scroll_arrived_after_scroll_end = false;
var scroll_end_arrived = false;
scroller.addEventListener("scroll", () => {
  if (scroll_end_arrived)
    scroll_arrived_after_scroll_end = true;
});
scroller.addEventListener("scrollend", () => {
  scroll_end_arrived = true;
});
function runTests() {
  promise_test (async () => {
    await waitForCompositorCommit();
    const scrollPromise = waitForScrollEvent(scroller);
    await smoothScroll(100, 200, 200, GestureSourceType.TOUCH_INPUT, 'down');
    // Wait for the scroll snap animation to finish.
    await scrollPromise;
    await waitForAnimationEndTimeBased(scrollPos);
    await waitUntil(() => { return scroll_end_arrived; });
    // Verify that scroll snap animation has finished before firing scrollend event.
    assert_false(scroll_arrived_after_scroll_end);
  }, "Tests that scrollend is fired after scroll snap animation completion.");

  promise_test (async () => {
    // Reset scroll state.
    scroller.scrollTo(0, 0);
    await waitForCompositorCommit();
    // Wait 2 additional rAFs before resetting the flags to avoid resetting
    // before the scrollend associated with the scrollTo call.
    await raf();
    await raf();
    scroll_end_arrived = false;
    scroll_arrived_after_scroll_end = false;

    const scrollPromise = waitForScrollEvent(scroller);
    await swipe(100, 200, 200, 'up');
    // Wait for the scroll snap animation to finish.
    await scrollPromise;
    await waitForAnimationEndTimeBased(scrollPos);
    await waitUntil(() => { return scroll_end_arrived; });
    // Verify that scroll snap animation has finished before firing scrollend event.
    assert_false(scroll_arrived_after_scroll_end);
  }, "Tests that scrollend is fired after fling snap animation completion.");
}
</script>
